<?php
/**
 * base Kit class
 *
 * This file is part of Webappkit, a packages system for PHP web apps
 * @link http://webappkit.net
 * @package webappkit
 * @author J.Ducastel <nospam0@ducastel.name>
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
 */

class WakKit implements iWakKit {
	/**
	 * @var string kit unique id
	 */
	protected $_id;

	/**
	 * @var array kit configuration data
	 */
	protected $_cfg=array();

	/**
	 * @var string physical path
	 */
	protected $_path;

    /**
	 * getter for tools. autoload tools when required
	 * @param string $name
	 * @return WakTool
	 */
	public function & __get($name) {
		if (substr($name,0,1)!='_'
		and !isset($this->$name)
		and isset($this->_cfg['tools'][$name])) {
			$this->_buildTool($name,$this->_cfg['tools'][$name]);
		}
		return $this->$name;
	}

    /**
	 * constructor
	 * @access private
	 * @param string kit id
	 * @todo do not build tools, use lazy loading with __get instead
	 */
	function __construct($id) {
		// setting config
		$this->_id=$id;
		$this->_path=webappkit::getPathFromId($id);
		$this->_cfg=webappkit::getCfgFromId($id);
		// setting tool members
		// deported to __get for lazy loading
		/*foreach ($this->_cfg['tools'] as $name => $class) {
			$this->_buildTool($name,$class);
		}*/
	}

	/**
	 * this method is the one to be implemented and used for requests handling kits
	 * @access public
	 * @return bool
	 */
	public function run() {
		throw new WakNotImplemented('kit '.$this->getId().' is not able to handle requests. method run() not implemented.');
		return false;
	}

	/**
	 * get kit's path
	 * @return string
	 */
	public function getPath() {
		return $this->_path;
	}

	/**
	 * get kit's id
	 */
	public function getId() {
		return $this->_id;
	}

	/**
	 * get kit's config
	 * @return array
	 */
	public function getCfg($key=null) {
		return $this->_cfg;
	}

	/**
	 * list subkits
	 * @access public
	 * @return array kits ids
	 */
	function listSubkits() {
		return Webappkit::listKits($this->getPath());
	}

	/**
	 * get a subkit instance if available
	 * @access public
	 * @param string subkit id (without the parent part)
	 * @return Webappkit
	 */
	function getSubkit($id) {
		return Webappkit::getKit($this->getId().'.'.$id);
	}

	/**
	 * get kit tools.
	 * May filter by class
	 * @access public
	 * @param string $of_class if provided, will return only tools from this class
	 * @return array name=>instance
	 */
	public function & getTools($of_class=null) {
		$tools=array();
		// listing tool members
        foreach ($this->_cfg['tools'] as $name => $class) {
            // filtering if required
            if ($of_class and $of_class!=$class)
                continue;
            $tools[$name]=&$this->$name;
        }
        return $tools;
	}

	/**
	 * tells if a tool has its custom config
	 * @access public
	 * @param string $tool tool's name
	 * @return bool
	 */
	public function toolHasConfig($tool) {
		$file=$this->getPath().$tool.'.tool.ini'; // echo $file;
		return file_exists($file) and is_file($file);
	}

	/**
	* loads tool's config ini file ( {name}.tool.ini )
	* @access protected
	* @param string $name tool's name
	* @return array|null|false
	*/
	protected function _getToolCfg($name) {
		// getting ini file
		$file=$this->getPath().$name.'.tool.ini'; // echo $file;
		if (!file_exists($file) or !is_file($file)) {
			return null;
		}
		// parsing, with sections
		$cfg=parse_ini_file($file,true);
		if (!is_array($cfg)) {
			//trigger_error("failed to parse $file");
			throw new WakBadCfg("failed to parse $file",500);
			return false;
		}
		return $cfg;
	}

	/**
	 * builds a tool member : create a tool member instance for the kit.
	 * Will try to load config from ini file
	 * @access protected
	 * @param string $name the member name given to tool
	 * @param string $class
	 * @return bool
	 */
	protected function _buildTool($name,$class) {
		// defining class
		if (!class_exists($class)) {
            throw new WakMissingClass("failed to build tool $name for kit {$this->_id} : class $class is missing");
			return false;
		}
		// trying to read config from ini file within self kit
		$cfg=$this->_getToolCfg($name);
		// calling factory method
			// $instance=$class::factory($this,$name);
		$instance=call_user_func(array($class,'toolFactory'),$this->getId(),$cfg);
		$this->$name=$instance;
		return true;
	}
}
